package ma.xin.shi.arxml.comm;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;

/**
 * 用于向 ARXML 文档中追加 XML 元素的工具类
 */
public class ArxmlElementAppender {

	/**
     * 添加一个没有文本内容的 XML 子节点
     *
     * 示例：
     *   <SHORT-NAME>FCM_UUID</SHORT-NAME>
     *
     * @param doc        当前文档对象
     * @param parent     父节点
     * @param tagName    标签名（如 "SHORT-NAME"）
     * @param textContent 要设置的文本内容
     */
    public static void appendElement(Document doc, Element parent, String tagName) {
        Element element = doc.createElement(tagName);
        parent.appendChild(element);
    }
    
    /**
     * 添加一个没有文本内容的 XML 子节点
     *
     * 示例：
     *   <SHORT-NAME>FCM_UUID</SHORT-NAME>
     *
     * @param doc        当前文档对象
     * @param parent     父节点
     * @param tagName    标签名（如 "SHORT-NAME"）
     * @param textContent 要设置的文本内容
     * @return Element: the Node Added
     */
    public static Element appendElementWithReturn(Document doc, Element parent, String tagName) {
        Element element = doc.createElement(tagName);
        parent.appendChild(element);
        
        return element;
    }
	
	/**
     * 添加一个带有文本内容的 XML 子节点
     *
     * 示例：
     *   <SHORT-NAME>FCM_UUID</SHORT-NAME>
     *
     * @param doc        当前文档对象
     * @param parent     父节点
     * @param tagName    标签名（如 "SHORT-NAME"）
     * @param textContent 要设置的文本内容
     */
    public static void appendElement(Document doc, Element parent, String tagName, String textContent) {
        Element element = doc.createElement(tagName);
        element.setTextContent(textContent);
        parent.appendChild(element);
    }
    
    /**
     * 添加一个带有文本内容的 XML 子节点
     *
     * 示例：
     *   <SHORT-NAME>FCM_UUID</SHORT-NAME>
     *
     * @param doc        当前文档对象
     * @param parent     父节点
     * @param tagName    标签名（如 "SHORT-NAME"）
     * @param textContent 要设置的文本内容
     * @return Element: the Node Added
     */
    public static Element appendElementWithReturn(Document doc, Element parent, String tagName, String textContent) {
        Element element = doc.createElement(tagName);
        element.setTextContent(textContent);
        parent.appendChild(element);
        
        return element;
    }

    /**
     * 添加一个仅包含标签、没有内容的 XML 子节点，并强制输出为双标签形式
     *
     * 示例：
     *   <CATEGORY></CATEGORY>
     *
     * @param doc       当前文档对象
     * @param parent    父节点
     * @param tagName   标签名（如 "CATEGORY"）
     * @return void
     */
    public static void appendElementEx(Document doc, Element parent, String tagName) {
        Element element = doc.createElement(tagName);
        
        // 关键点：插入 Unicode 零宽度空格（\u200B），确保不被优化掉
        Text hiddenSpace = doc.createTextNode("\u200B");
        element.appendChild(hiddenSpace);
        
        parent.appendChild(element);
    }

    /**
     * 将 Document 转换为 String，并控制是否禁用自闭合标签
     *
     * @param doc           要转换的 Document
     * @param forceNoSelfClosing  是否强制禁用自闭合标签（仅对空元素生效）
     * @return              格式化后的 XML 字符串
     */
    public static String documentToString(Document doc, boolean forceNoSelfClosing) {
        try {
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            
            // 默认设置（格式化输出）
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
            
            // 仅在 forceNoSelfClosing=true 时禁用自闭合标签
            if (forceNoSelfClosing) {
                // 某些实现支持此属性来禁用自闭合优化
                try {
                    transformer.setOutputProperty("http://www.oracle.com/xml/is-standalone", "yes");
                } catch (Exception ignored) {}
            }
            
            StringWriter writer = new StringWriter();
            transformer.transform(new DOMSource(doc), new StreamResult(writer));
            return writer.toString();
        } catch (Exception e) {
            throw new RuntimeException("Failed to convert Document to String", e);
        }
    }
}